//
// Created by jsz on 2021/6/10.
//
// 使用unix套接字，实现全双工通道
//
#include "channel.h"
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>


#define DEFAULT_PATH    "/tmp/fake_port_device"

void PrintfError(char *fmt, ...)
{
    va_list ap;

    va_start(ap, fmt);
    vprintf(fmt, ap);
    va_end(ap);
}

int channel_open(const char *channel)
{
    struct sockaddr_un address;
    int sock;
    size_t addrLength;

    if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) {
        PrintfError("socket failed\n");
        return -1;
    }

    address.sun_family = AF_UNIX;	/* Unix domain socket */
    if (channel == 0) {
        strcpy(address.sun_path, DEFAULT_PATH);
    }
    else {
        strcpy(address.sun_path, channel);
    }
    /* The total length of the address includes the sun_family element */
    addrLength = sizeof(address.sun_family) + strlen(address.sun_path);

    if (connect(sock, (struct sockaddr *) &address, addrLength)) {
        PrintfError("connect failed\n");
        return -1;
    }
    return sock;
}

int channel_open_passive(const char *channel)
{
    struct sockaddr_un address;	// #include <sys/un.h>
    int sock, conn;
    socklen_t addrLength;

    // AF 表示ADDRESS FAMILY 地址族
    // PF 表示PROTOCL FAMILY 协议族
    if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) {
        PrintfError("socket failed\n");
        return -1;
    }

    address.sun_family = AF_UNIX;       /* Unix domain socket */
    if (channel == NULL) {
        strcpy(address.sun_path, DEFAULT_PATH);
    }
    else {
        strcpy(address.sun_path, channel);
    }

    /* Remove any preexisting socket (or other file) */
    unlink(address.sun_path);

    /* The total length of the address includes the sun_family element */
    addrLength = sizeof(address.sun_family) + strlen(address.sun_path);

    if (bind(sock, (struct sockaddr *)&address, addrLength)) {
        PrintfError("bind failed\n");
        return -1;
    }

    if (listen(sock, 5)) {
        PrintfError("listen failed\n");
        return -1;
    }
    return sock;
}

int channel_write(int fd, void *buff, int count)
{
    return write(fd, buff, count);
}

int channel_read(int fd, void *buff, int count)
{
    return read(fd, buff, count);
}


int channel_wait(int fd)
{
    int ret;
    socklen_t slen;
    struct sockaddr_un address;

    slen = sizeof(address);
    ret = accept(fd, (struct sockaddr *)&address, &slen);
    if (ret < 0) {
        perror("accept");
    }
}

int channel_close(int fd)
{
    return close(fd);
}

